package com.dc.config.shiro;

import com.dc.common.constant.CustomConstants;
import com.dc.common.constant.ResultStatus;
import com.dc.common.utils.ObjectMapperUtil;
import com.dc.common.utils.ServletUtil;
import com.dc.common.utils.ShiroUtil;
import com.dc.common.utils.StringUtil;
import com.dc.common.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author zhuangcy
 * @date 2021/1/18
 * @description 自定义过滤器
 */
@Slf4j
public class MyFilter extends FormAuthenticationFilter {

    /**
     * 判断请求是否需要认证授权（请求头中携带 token 则代表需要验证）
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        HttpServletRequest req = WebUtils.toHttp(request);
        String token = req.getHeader(CustomConstants.TOKEN_NAME);
        if (StringUtil.isEmpty(token)) {
            token = req.getParameter(CustomConstants.TOKEN_NAME);
        }
        return StringUtil.isNotEmpty(token) && ShiroUtil.validateSession(token);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        //登录校验返回false则执行该方法，此时给response放入登录超时返回json，最后会在过滤链全部执行结束时返回到前端
        ServletUtil.renderString(WebUtils.toHttp(response), ObjectMapperUtil.toJSON(ResultVo.failed().code(ResultStatus.NOT_CERTIFIED_CODE.getCode()).msg(ResultStatus.NOT_CERTIFIED_CODE.getMsg())));
        return false;
    }

    /**
     * 对跨域提供支持
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,PATCH,DELETE");
        //*号在IE 浏览器上无法完全识别跨域，所以需要写全，这样才能兼容IE 和 谷歌
        //参考：https://blog.csdn.net/qq_37164847/article/details/106327081
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "authorization,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type");
        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }
}
